package com.raven.craft.code.generator.config;

import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.google.common.collect.Sets;
import com.raven.craft.code.generator.common.util.JsonUtil;
import com.raven.craft.code.generator.mysql.repo.entity.Column;
import com.raven.craft.code.generator.mysql.repo.entity.Table;
import com.raven.craft.code.generator.mysql.repo.mapper.ColumnMapper;
import com.raven.craft.code.generator.mysql.repo.mapper.TableMapper;
import com.raven.craft.code.generator.mysql.repo.mapper.TableStatusMapper;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import lombok.extern.slf4j.Slf4j;

import java.util.Comparator;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @author raven
 * @date 2020/08/28
 **/
@Slf4j
@Getter
@Setter
@ToString
public class MysqlContext {

    private String database;
    private List<Table> tables;

    public static MysqlContext create(MysqlProperties mysqlProperties,
                                      TableMapper tableMapper, ColumnMapper columnMapper, TableStatusMapper tableStatusMapper) {
        MysqlContext context = new MysqlContext();
        context.setDatabase(mysqlProperties.getDatabase());
        context.setTables(getTables(mysqlProperties, tableMapper, columnMapper, tableStatusMapper));
        return context;
    }

    private static List<Table> getTables(MysqlProperties properties, TableMapper tableMapper, ColumnMapper columnMapper,
                                         TableStatusMapper tableStatusMapper) {
        Set<String> tableNames = getTableNames(properties, tableMapper);

        List<Table> tables = tableNames.stream()
                .map(tableName -> new Table(tableName, columnMapper.listAll(tableName), tableStatusMapper.getByTableName(tableName)))
                .sorted(Comparator.comparing(Table::getName))
                .collect(Collectors.toList());
        tables = filterTablesIncludeColumn(properties, tables);
        tables = filterTablesExcludeColumn(properties, tables);

        log.info("tables: {}", JsonUtil.toJson(tables));
        return tables;
    }

    private static Set<String> getTableNames(MysqlProperties properties, TableMapper tableMapper) {
        Set<String> tableNames;
        if (CollectionUtils.isEmpty(properties.getIncludeTables())) {
            tableNames = tableMapper.list(properties.getDatabase(), properties.getTablePattern());
        } else {
            tableNames = Sets.newHashSet(properties.getIncludeTables());
        }

        // 剔除 excludeTables 中的表
        if (!CollectionUtils.isEmpty(properties.getExcludeTables())) {
            tableNames.removeAll(properties.getExcludeTables());
        }
        return tableNames;
    }

    /**
     * 过滤必须包含 includeColumns 中字段的表
     */
    private static List<Table> filterTablesIncludeColumn(MysqlProperties properties, List<Table> tables) {
        if (!CollectionUtils.isEmpty(properties.getIncludeColumns())) {
            tables = tables.stream().filter(e -> e.getColumns().stream()
                    .map(Column::getField).collect(Collectors.toSet())
                    .containsAll(properties.getIncludeColumns()))
                    .collect(Collectors.toList());
        }
        return tables;
    }

    /**
     * 过滤必须不包含 excludeColumns 中字段的表
     */
    private static List<Table> filterTablesExcludeColumn(MysqlProperties properties, List<Table> tables) {
        if (!CollectionUtils.isEmpty(properties.getExcludeColumns())) {
            tables = tables.stream().filter(e -> {
                Set<String> columnNames = e.getColumns().stream()
                        .map(Column::getField).collect(Collectors.toSet());
                for (String c : columnNames) {
                    if (properties.getExcludeColumns().contains(c)) {
                        return false;
                    }
                }
                return true;
            }).collect(Collectors.toList());
        }
        return tables;
    }

}
